package com.ctshk.rpc.train.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ctshk.common.constant.RedisConstants;
import com.ctshk.common.dto.Result;
import com.ctshk.common.enums.IsDeletedCode;
import com.ctshk.common.enums.IsValidCode;
import com.ctshk.common.enums.SystemError;
import com.ctshk.common.enums.bus.BusLineStatusCode;
import com.ctshk.common.exception.BusinessException;
import com.ctshk.common.model.PageResponse;
import com.ctshk.common.model.TokenUser;
import com.ctshk.common.utils.EntityUtil;
import com.ctshk.common.utils.SnowflakeIdWorker;
import com.ctshk.rpc.train.dto.*;
import com.ctshk.rpc.train.dto.es.TrainNumberCacheDTO;
import com.ctshk.rpc.train.dto.es.TrainStopStationCacheDTO;
import com.ctshk.rpc.train.entity.TrainNumber;
import com.ctshk.rpc.train.entity.TrainNumberSeat;
import com.ctshk.rpc.train.entity.TrainNumberSeatLevel;
import com.ctshk.rpc.train.entity.TrainStopStation;
import com.ctshk.rpc.train.mapper.TrainNumberMapper;
import com.ctshk.rpc.train.mapper.TrainNumberSeatLevelMapper;
import com.ctshk.rpc.train.mapper.TrainNumberSeatMapper;
import com.ctshk.rpc.train.mapper.TrainStopStationMapper;
import com.ctshk.rpc.train.req.*;
import com.ctshk.rpc.train.service.ITrainNumberService;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;


/**
 * <p>
 * 火车车次表 服务实现类
 * </p>
 *
 * @author 彭柳霖
 * @since 2021-03-10
 */
@DubboService
public class TrainNumberServiceImpl extends ServiceImpl<TrainNumberMapper, TrainNumber> implements ITrainNumberService {

    @Autowired
    private TrainNumberMapper trainNumberMapper;

    @Autowired
    private TrainNumberSeatLevelMapper trainNumberSeatLevelMapper;

    @Autowired
    private TrainNumberSeatMapper trainNumberSeatMapper;

    @Autowired
    private TrainStopStationMapper trainStopStationMapper;

    @Autowired
    RedisTemplate<String, String> redisTemplate;

    /**
     * 火车车次列表-分页查询
     *
     * @param req
     * @return
     */
    @Override
    public PageResponse<TrainNumberListDTO> queyList(TrainNumberPageReq req) {

        IPage<TrainNumberListDTO> agentPage = new Page<>(req.getPageNo(), req.getPageSize());
        agentPage = trainNumberMapper.queryList(req, agentPage);
        PageResponse<TrainNumberListDTO> result = new PageResponse<>(agentPage.getRecords(), agentPage.getCurrent() == 1,
                agentPage.getTotal() <= (agentPage.getCurrent() * agentPage.getSize()),
                agentPage.getTotal(), agentPage.getCurrent(), agentPage.getSize());
        return result;
    }

    /**
     * 新增火车车次信息
     *
     * @param trainNumberReq
     * @param user
     */
    @Transactional(rollbackFor = BusinessException.class)
    @Override
    public Result saveTrainNumber(TrainNumberReq trainNumberReq, TokenUser user) {

        //保存
        TrainNumber trainNumber = new TrainNumber();
        BeanUtils.copyProperties(trainNumberReq, trainNumber);
        Long trainNumberId = SnowflakeIdWorker.nextId();
        trainNumber.setId(trainNumberId);
        trainNumber.setCreateId(user.getId());
        trainNumber.setGmtCreate(LocalDateTime.now());
        trainNumber.setStatus(IsValidCode.VALID.getCode());
        trainNumber.setIsDeleted(IsDeletedCode.NO.getCode());

        /*//计算终点站-始发站的天数 如果天数是前端传来的，则注释的代码可以删除
        long day = trainNumberReq.getTerminusTime().toLocalDate().toEpochDay() - trainNumberReq.getDepartureTime().toLocalDate().toEpochDay();
        trainNumber.setDay(String.valueOf(day));*/
        trainNumberMapper.insert(trainNumber);

        //保存座位等级信息
        List<TrainNumberSeatLevelReq> trainNumberSeatLevelReqList = trainNumberReq.getTrainNumberSeatLevelReqList();
        for (TrainNumberSeatLevelReq seatLevelReq : trainNumberSeatLevelReqList) {
            TrainNumberSeatLevel seatLevel = EntityUtil.copy(seatLevelReq, TrainNumberSeatLevel.class);
            seatLevel.setId(SnowflakeIdWorker.nextId());
            seatLevel.setTrainNumberId(trainNumberId);
            trainNumberSeatLevelMapper.insert(seatLevel);
        }

        //保存座位信息
        List<TrainNumberSeatReq> trainNumberSeatReqList = trainNumberReq.getTrainNumberSeatReqList();
        for (TrainNumberSeatReq seatReq : trainNumberSeatReqList) {
            TrainNumberSeat trainNumberSeat = EntityUtil.copy(seatReq, TrainNumberSeat.class);
            trainNumberSeat.setId(SnowflakeIdWorker.nextId());
            trainNumberSeat.setTrainNumberId(trainNumberId);
            trainNumberSeatMapper.insert(trainNumberSeat);
        }

        //保存火车经停站信息
        List<TrainStopStationReq> stopStationReqList = trainNumberReq.getTrainStopStationReqList();
        for (TrainStopStationReq stopStationReq : stopStationReqList) {
            TrainStopStation trainStopStation = EntityUtil.copy(stopStationReq, TrainStopStation.class);
            if (!StringUtils.hasText(trainStopStation.getStationName())) {
                continue;
            }
            trainStopStation.setId(SnowflakeIdWorker.nextId());
            trainStopStation.setTrainNumberId(trainNumberId);
            // 停留分钟 = 出发时间ArriveTime - 到站时间LevelTime
            Duration duration = Duration.between(stopStationReq.getLevelTime(), stopStationReq.getArriveTime());
            Long duraMinute = duration.toMinutes();
            trainStopStation.setStopTime(duraMinute);
            trainStopStationMapper.insert(trainStopStation);
        }
        //添加起始站
        TrainStopStation beiginStation = new TrainStopStation();
        beiginStation.setId(SnowflakeIdWorker.nextId());
        beiginStation.setTrainNumberId(trainNumberId);
        beiginStation.setStationId(trainNumberReq.getDepartureStationId());
        beiginStation.setStationName(trainNumberReq.getDepartureStationName());
        beiginStation.setArriveTime(trainNumberReq.getDepartureTime());

        trainStopStationMapper.insert(beiginStation);

        //添加结束站
        TrainStopStation endStation = new TrainStopStation();
        endStation.setId(SnowflakeIdWorker.nextId());
        endStation.setTrainNumberId(trainNumberId);
        endStation.setStationId(trainNumberReq.getTerminusId());
        endStation.setStationName(trainNumberReq.getTerminusName());
        endStation.setLevelTime(trainNumberReq.getTerminusTime());
        trainStopStationMapper.insert(endStation);
        return Result.success();
    }

    /**
     * 修改火车车次信息
     *
     * @param trainNumberReq
     * @param user
     */
    @Transactional(rollbackFor = BusinessException.class)
    @Override
    public Result updateTrainNumber(TrainNumberReq trainNumberReq, TokenUser user) {


        //更新火车车次信息
        TrainNumber trainNumber = trainNumberMapper.selectById(trainNumberReq.getId());
        if (Objects.isNull(trainNumber)) {
            return Result.failed(SystemError.TRAIN_PRODUCT_14001);
        }
        BeanUtils.copyProperties(trainNumberReq, trainNumber);

        trainNumber.setModifiedId(user.getId());
        trainNumber.setGmtModified(LocalDateTime.now());
        trainNumberMapper.updateById(trainNumber);

        //更新座位等级信息(先删后插入)
        trainNumberSeatLevelMapper.delete(new QueryWrapper<TrainNumberSeatLevel>().lambda().eq(TrainNumberSeatLevel::getTrainNumberId, trainNumberReq.getId()));
        List<TrainNumberSeatLevelReq> trainNumberSeatLevelReqList = trainNumberReq.getTrainNumberSeatLevelReqList();
        for (TrainNumberSeatLevelReq seatLevelReq : trainNumberSeatLevelReqList) {
            TrainNumberSeatLevel seatLevel = EntityUtil.copy(seatLevelReq, TrainNumberSeatLevel.class);
            seatLevel.setId(SnowflakeIdWorker.nextId());
            seatLevel.setTrainNumberId(trainNumberReq.getId());
            trainNumberSeatLevelMapper.insert(seatLevel);
        }

        //更新座位信息(先删后插入)
        trainNumberSeatMapper.delete(new QueryWrapper<TrainNumberSeat>().lambda().eq(TrainNumberSeat::getTrainNumberId, trainNumberReq.getId()));
        List<TrainNumberSeatReq> trainNumberSeatReqList = trainNumberReq.getTrainNumberSeatReqList();
        for (TrainNumberSeatReq seatReq : trainNumberSeatReqList) {
            TrainNumberSeat trainNumberSeat = EntityUtil.copy(seatReq, TrainNumberSeat.class);
            trainNumberSeat.setId(SnowflakeIdWorker.nextId());
            trainNumberSeat.setTrainNumberId(trainNumberReq.getId());
            trainNumberSeatMapper.insert(trainNumberSeat);
        }


        //更新火车经停站信息(先删后插入)
        trainStopStationMapper.delete(new QueryWrapper<TrainStopStation>().lambda().eq(TrainStopStation::getTrainNumberId, trainNumberReq.getId()));
        List<TrainStopStationReq> stopStationReqList = trainNumberReq.getTrainStopStationReqList();
        for (TrainStopStationReq stopStationReq : stopStationReqList) {
            TrainStopStation trainStopStation = EntityUtil.copy(stopStationReq, TrainStopStation.class);
            trainStopStation.setId(SnowflakeIdWorker.nextId());
            trainStopStation.setTrainNumberId(trainNumberReq.getId());
            Duration duration = Duration.between(stopStationReq.getArriveTime(), stopStationReq.getLevelTime());
            Long duraMinute = duration.toMinutes();
            trainStopStation.setStopTime(duraMinute);
            trainStopStationMapper.insert(trainStopStation);
        }

        //添加起始站
        TrainStopStation beiginStation = new TrainStopStation();
        beiginStation.setId(SnowflakeIdWorker.nextId());
        beiginStation.setTrainNumberId(trainNumberReq.getId());
        beiginStation.setStationId(trainNumberReq.getDepartureStationId());
        beiginStation.setStationName(trainNumberReq.getDepartureStationName());
        beiginStation.setLevelTime(trainNumberReq.getDepartureTime());
        trainStopStationMapper.insert(beiginStation);

        //添加结束站
        TrainStopStation endStation = new TrainStopStation();
        endStation.setId(SnowflakeIdWorker.nextId());
        endStation.setTrainNumberId(trainNumberReq.getId());
        endStation.setStationId(trainNumberReq.getTerminusId());
        endStation.setStationName(trainNumberReq.getTerminusName());
        endStation.setArriveTime(trainNumberReq.getTerminusTime());
        trainStopStationMapper.insert(endStation);

        return Result.success();
    }

    @Override
    public TrainNumberDTO queryDetail(Long id) {

        TrainNumber trainNumber = trainNumberMapper.selectById(id);
        if (Objects.isNull(trainNumber)) {
            return null;
        }
        TrainNumberDTO trainNumberDTO = EntityUtil.copy(trainNumber, TrainNumberDTO.class);


        //查询火车席位等级信息
        List<TrainNumberSeatLevel> busLineSeatList = trainNumberSeatLevelMapper.selectList(new QueryWrapper<TrainNumberSeatLevel>().lambda().eq(TrainNumberSeatLevel::getTrainNumberId, id));
        List<TrainNumberSeatLevelDTO> trainNumberSeatLevelDTOList = EntityUtil.copyList(busLineSeatList, TrainNumberSeatLevelDTO.class);
        trainNumberDTO.setTrainNumberSeatLevelDTOList(trainNumberSeatLevelDTOList);

        //查询火车车次座位信息
        List<TrainNumberSeat> trainNumberSeatList = trainNumberSeatMapper.selectList(new QueryWrapper<TrainNumberSeat>().lambda().eq(TrainNumberSeat::getTrainNumberId, id));
        List<TrainNumberSeatDTO> trainNumberSeatDTOList = EntityUtil.copyList(trainNumberSeatList, TrainNumberSeatDTO.class);
        trainNumberDTO.setTrainNumberSeatDTOList(trainNumberSeatDTOList);


        //查询火车经停站信息
        List<TrainStopStation> trainStopStationList = trainStopStationMapper.selectList(new QueryWrapper<TrainStopStation>().lambda().eq(TrainStopStation::getTrainNumberId, id));
        List<TrainStopStationDTO> trainStopStationDTOList = EntityUtil.copyList(trainStopStationList, TrainStopStationDTO.class);
        trainNumberDTO.setTrainStopStationDTOList(trainStopStationDTOList);

        if (trainStopStationDTOList.size() > 2) {
            List<TrainStopStationDTO> limit = trainStopStationDTOList.stream().limit(trainStopStationDTOList.size() - 2).collect(Collectors.toList());
            trainNumberDTO.setTrainStopStationDTOWithoutStartAndEndList(limit);
        }

        return trainNumberDTO;
    }

    /**
     * 火车车次有效无效设置
     *
     * @param id
     */
    @Transactional(rollbackFor = BusinessException.class)
    @Override
    public Result isValid(long id, TokenUser user) {

        TrainNumber trainNumber = trainNumberMapper.selectById(id);
        if (Objects.isNull(trainNumber)) {
            return Result.failed(SystemError.TRAIN_PRODUCT_14001);
        }

        if (IsValidCode.VALID.getCode().equals(trainNumber.getStatus())) {
            trainNumber.setStatus(IsValidCode.IN_VALID.getCode()); //设置为无效
        } else {
            trainNumber.setStatus(IsValidCode.VALID.getCode()); //设置为有效
        }
        trainNumber.setModifiedId(user.getId());
        trainNumber.setGmtModified(LocalDateTime.now());
        trainNumberMapper.updateById(trainNumber);

        return Result.success();
    }

    @Override
    public List<TrainNumberDTO> queryTrainNumber(TrainNumberQueryReq trainNumberQueryReq) {
        QueryWrapper<TrainNumber> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(TrainNumber::getIsDeleted, IsDeletedCode.NO.getCode()).eq(TrainNumber::getStatus, IsValidCode.VALID.getCode()).orderByDesc(TrainNumber::getGmtCreate);

        //查询条件
        if (!StringUtils.isEmpty(trainNumberQueryReq.getRailwayCorporationName())) {
            queryWrapper.lambda().like(TrainNumber::getRailwayCorporationName, trainNumberQueryReq.getRailwayCorporationName());
        }

        if (!StringUtils.isEmpty(trainNumberQueryReq.getDepartureCityName())) {
            queryWrapper.lambda().like(TrainNumber::getDepartureCityName, trainNumberQueryReq.getDepartureCityName());
        }

        if (!StringUtils.isEmpty(trainNumberQueryReq.getArriveCityName())) {
            queryWrapper.lambda().like(TrainNumber::getArriveCityName, trainNumberQueryReq.getArriveCityName());
        }

        List<TrainNumber> busLineList = trainNumberMapper.selectList(queryWrapper);
        List<TrainNumberDTO> trainNumberDTOList = EntityUtil.copyList(busLineList, TrainNumberDTO.class);
        return trainNumberDTOList;
    }


    /**
     * 根据车次id查询火车经停站信息
     *
     * @param trainId
     * @return
     */
    @Override
    public List<TrainStopStationDTO> queryStopStaionByTrainId(Long trainId) {

        List<TrainStopStation> trainStopStationList = trainStopStationMapper.selectList(new QueryWrapper<TrainStopStation>().lambda().eq(TrainStopStation::getTrainNumberId, trainId));

        List<TrainStopStation> result = new ArrayList<>();
        if (trainStopStationList.size() >= 3) {
            // 将倒数第二位的出发站移动到首位
            int index = trainStopStationList.size() - 2;
            TrainStopStation trainStopStation = trainStopStationList.get(index);
            trainStopStationList.remove(index);
            result.add(trainStopStation);
            result.addAll(trainStopStationList);
        }

        List<TrainStopStationDTO> trainStopStationDTOList = EntityUtil.copyList(result.size() == 0 ? trainStopStationList : result, TrainStopStationDTO.class);
        return trainStopStationDTOList;
    }

    @Override
    public PageResponse<TrainNumberConditionListDTO> queryTrainNumberConditionList(TrainNumberPageReq req) {
        QueryWrapper<TrainNumber> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(TrainNumber::getIsDeleted, IsDeletedCode.NO.getCode()).eq(TrainNumber::getStatus, IsValidCode.VALID.getCode()).orderByDesc(TrainNumber::getGmtCreate);

        //查询条件
        if (!StringUtils.isEmpty(req.getName())) {
            queryWrapper.lambda().like(TrainNumber::getTrainNumberName, req.getName());
        }

        List<TrainNumber> trainNumberListList = trainNumberMapper.selectList(queryWrapper);
        List<TrainNumberConditionListDTO> TrainNumberConditionListDTOList = EntityUtil.copyList(trainNumberListList, TrainNumberConditionListDTO.class);

        IPage<TrainNumberConditionListDTO> agentPage = new Page<>(req.getPageNo(), req.getPageSize());
        agentPage.setRecords(TrainNumberConditionListDTOList);
        PageResponse<TrainNumberConditionListDTO> result = new PageResponse<>(agentPage.getRecords(), agentPage.getCurrent() == 1,
                agentPage.getTotal() <= (agentPage.getCurrent() * agentPage.getSize()),
                agentPage.getTotal(), agentPage.getCurrent(), agentPage.getSize());
        return result;
    }

    @Override
    public List<TrainNumberCacheDTO> findTrainNumberList(List<Long> ids, LocalDateTime now) {
        LambdaQueryWrapper<TrainNumber> wrapper = Wrappers.<TrainNumber>lambdaQuery().eq(TrainNumber::getIsDeleted, IsDeletedCode.NO.getCode());
        wrapper.eq(TrainNumber::getStatus, BusLineStatusCode.VALID.getCode());
        if (now != null) {
            LocalDateTime updateTime = JSON.parseObject(redisTemplate.opsForValue().get(RedisConstants.TRAIN_UPDATE_TIME), LocalDateTime.class);
            wrapper.ge(now.isAfter(updateTime), TrainNumber::getGmtModified, now);
        }
        wrapper.in(ids != null && ids.size() > 0, TrainNumber::getId, ids);
        List<TrainNumber> busLines = trainNumberMapper.selectList(wrapper);
        List<TrainNumberCacheDTO> numberCacheDTOS = EntityUtil.copyList(busLines, TrainNumberCacheDTO.class);
        for (TrainNumberCacheDTO trainNumber : numberCacheDTOS) {
            //查询火车经停站信息
            List<TrainStopStationCacheDTO> trainStopStationDTOList = EntityUtil.copyList(this.queryStopStaionByTrainId(trainNumber.getId()), TrainStopStationCacheDTO.class);
            trainNumber.setTrainStopStationCacheDTOS(trainStopStationDTOList);
        }
        return numberCacheDTOS;
    }


}
